﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace The_LarX
{
    public enum SideSprite
    {
        Left, Right, Up, Down
    }
    public class SquareSpriteAndChildren
    {
        public Sprite2D Sprite;
        public Dictionary<SideSprite, Sprite2D> SideSprite;        

        public SquareSpriteAndChildren(Sprite2D s)
        {
            SideSprite = new Dictionary<SideSprite, Sprite2D>();
            this.Sprite = s;
        }

        public override string ToString()
        {
            return Sprite.Text;
        }
    }

    public class LarXKeyboard : GuideLikeComponent
    {
        public delegate void LarXKeyboardCallback(string text);

        public LarXKeyboardCallback Callback;

        private List<SquareSpriteAndChildren> Squares;
        private List<Sprite2D> DefaultTextsLowerCase;
        private List<Sprite2D> DefaultTextsUpperCase;

        private Sprite2D TextSquare;
        private Sprite2D SquareText;

        private SquareSpriteAndChildren[,] SquaresVector;

        private Texture2D Box;

        private Sprite2D ControlSprite;

        public Color BackgroundColor = Color.Blue;

        public LarXKeyboard()
        {
            Load();
        }

        private delegate float MethodTextCenter(Sprite2D k);
        private float UpperTextY(Sprite2D s)
        {
            return s.Position.Y + (s.SizeRectangle.Height / 12);
        }
        private float RightTextX(Sprite2D s)
        {
            return s.Position.X + (s.SizeRectangle.Width) - (s.SizeRectangle.Width / 6);
        }
        private float LeftTextX(Sprite2D s)
        {
            return s.Position.X + (s.SizeRectangle.Width / 12);
        }
        private float DownTextY(Sprite2D s)
        {
            return s.Position.Y + (s.SizeRectangle.Height) - (s.SizeRectangle.Height / 5);
        }

        private void Load()
        {
            PresentationParameters pp = Engine.GraphicsDevice.PresentationParameters;
            int ScreenWidth = pp.BackBufferWidth;
            int ScreenHeight = pp.BackBufferHeight;

            Box = Engine.RenderManager.Tex;

            float MaxSquareSize = ScreenHeight / 4;

            Squares = new List<SquareSpriteAndChildren>();
            DefaultTextsUpperCase = new List<Sprite2D>();
            DefaultTextsLowerCase = new List<Sprite2D>();

            TextSquare = new Sprite2D("Engine\\Textures\\tex_box", new Vector2(50));
            TextSquare.Size = new Vector2(9, 100f / 128f);
            TextSquare.Color = Color.Gray;

            SquareText = new Sprite2D(new Vector2(70), "");

            ControlSprite = new Sprite2D("Engine\\Textures\\tex_controller", Vector2.Zero);
            ControlSprite.Size = new Vector2(0.5f);

            SquaresVector = new SquareSpriteAndChildren[3, 3];

            for (int i = 0; i < 3; i++)
            {
                for (int k = 0; k < 3; k++)
                {
                    Sprite2D sprite = new Sprite2D("Engine\\Textures\\tex_box", new Vector2((i * MaxSquareSize) + (ScreenWidth / 2), (k * MaxSquareSize) + (ScreenHeight / 4)));
                    sprite.Size = new Vector2(((float)(ScreenHeight / 4) / 128f) * 0.8f);
                    sprite.Update();                    
                    SquareSpriteAndChildren mother = new SquareSpriteAndChildren(sprite);
                    Squares.Add(mother);
                    SquaresVector[i, k] = mother;

                    switch (i)
                    {
                        case 0:
                            switch (k)
                            {
                                case 1:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("Y", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("Z", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    break;
                                case 2:                                   
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("U", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("V", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("W", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("X", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                            };
                            break;
                        case 1:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("A", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("B", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("C", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("D", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                                case 1:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("SPACE", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("<-", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    break;
                                case 2:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("Q", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("R", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("S", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("T", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                            };
                            break;
                        case 2:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("E", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("F", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("G", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("H", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                                case 1:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("I", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("J", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("K", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("L", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                                case 2:
                                    mother.SideSprite.Add(SideSprite.Up, CreateSprite("M", sprite, UpperTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Right, CreateSprite("N", sprite, RightTextX, DefaultTextsUpperCase, true));
                                    mother.SideSprite.Add(SideSprite.Down, CreateSprite("O", sprite, DownTextY, DefaultTextsUpperCase, false));
                                    mother.SideSprite.Add(SideSprite.Left, CreateSprite("P", sprite, LeftTextX, DefaultTextsUpperCase, true));
                                    break;
                            };
                            break;
                    };
                }
            }
        }

        private bool UpperCase = true;
        private bool Numbers = false;

        private void SetToUpperCase()
        {
            Numbers = false;
            UpperCase = true;
            for (int i = 0; i < 3; i++)
            {
                for (int k = 0; k < 3; k++)
                {
                    SquareSpriteAndChildren mother = SquaresVector[i, k];
                    switch (i)
                    {
                        case 0:
                            switch (k)
                            {
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = "Y";
                                    mother.SideSprite[SideSprite.Right].Text = "Z";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "U";
                                    mother.SideSprite[SideSprite.Right].Text = "V";
                                    mother.SideSprite[SideSprite.Down].Text = "W";
                                    mother.SideSprite[SideSprite.Left].Text = "X";
                                    break;
                            };
                            break;
                        case 1:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "A";
                                    mother.SideSprite[SideSprite.Right].Text = "B";
                                    mother.SideSprite[SideSprite.Down].Text = "C";
                                    mother.SideSprite[SideSprite.Left].Text = "D";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "Q";
                                    mother.SideSprite[SideSprite.Right].Text = "R";
                                    mother.SideSprite[SideSprite.Down].Text = "S";
                                    mother.SideSprite[SideSprite.Left].Text = "T";
                                    break;
                            };
                            break;
                        case 2:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "E";
                                    mother.SideSprite[SideSprite.Right].Text = "F";
                                    mother.SideSprite[SideSprite.Down].Text = "G";
                                    mother.SideSprite[SideSprite.Left].Text = "H";
                                    break;
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = "I";
                                    mother.SideSprite[SideSprite.Right].Text = "J";
                                    mother.SideSprite[SideSprite.Down].Text = "K";
                                    mother.SideSprite[SideSprite.Left].Text = "L";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "M";
                                    mother.SideSprite[SideSprite.Right].Text = "N";
                                    mother.SideSprite[SideSprite.Down].Text = "O";
                                    mother.SideSprite[SideSprite.Left].Text = "P";
                                    break;
                            };
                            break;
                    };
                }
            }
        }
        private void SetNumbers()
        {
            Numbers = true;
            for (int i = 0; i < 3; i++)
            {
                for (int k = 0; k < 3; k++)
                {
                    SquareSpriteAndChildren mother = SquaresVector[i, k];
                    switch (i)
                    {
                        case 0:
                            switch (k)
                            {
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = ""; //y 
                                    mother.SideSprite[SideSprite.Right].Text = ""; //z
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = ""; //u
                                    mother.SideSprite[SideSprite.Right].Text = "";//v
                                    mother.SideSprite[SideSprite.Down].Text = "";//w
                                    mother.SideSprite[SideSprite.Left].Text = "";//x
                                    break;
                            };
                            break;
                        case 1:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "1";
                                    mother.SideSprite[SideSprite.Right].Text = "2";
                                    mother.SideSprite[SideSprite.Down].Text = "3";
                                    mother.SideSprite[SideSprite.Left].Text = "4";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "";//q
                                    mother.SideSprite[SideSprite.Right].Text = "";//r
                                    mother.SideSprite[SideSprite.Down].Text = "";//s
                                    mother.SideSprite[SideSprite.Left].Text = "";//t
                                    break;
                            };
                            break;
                        case 2:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "5";
                                    mother.SideSprite[SideSprite.Right].Text = "6";
                                    mother.SideSprite[SideSprite.Down].Text = "7";
                                    mother.SideSprite[SideSprite.Left].Text = "8";
                                    break;
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = "9";
                                    mother.SideSprite[SideSprite.Right].Text = "0";
                                    mother.SideSprite[SideSprite.Down].Text = "";//k
                                    mother.SideSprite[SideSprite.Left].Text = "";//l
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "";//m
                                    mother.SideSprite[SideSprite.Right].Text = "";//n
                                    mother.SideSprite[SideSprite.Down].Text = "";//o
                                    mother.SideSprite[SideSprite.Left].Text = "";//p
                                    break;
                            };
                            break;
                    };
                }
            }
        }
        private void SetToLowerCase()
        {
            UpperCase = false;
            Numbers = false;
            for (int i = 0; i < 3; i++)
            {
                for (int k = 0; k < 3; k++)
                {
                    SquareSpriteAndChildren mother = SquaresVector[i, k];
                    switch (i)
                    {
                        case 0:
                            switch (k)
                            {
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = "y";
                                    mother.SideSprite[SideSprite.Right].Text = "z";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "u";
                                    mother.SideSprite[SideSprite.Right].Text = "v";
                                    mother.SideSprite[SideSprite.Down].Text = "w";
                                    mother.SideSprite[SideSprite.Left].Text = "x";
                                    break;
                            };
                            break;
                        case 1:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "a";
                                    mother.SideSprite[SideSprite.Right].Text = "b";
                                    mother.SideSprite[SideSprite.Down].Text = "c";
                                    mother.SideSprite[SideSprite.Left].Text = "d";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "q";
                                    mother.SideSprite[SideSprite.Right].Text = "r";
                                    mother.SideSprite[SideSprite.Down].Text = "s";
                                    mother.SideSprite[SideSprite.Left].Text = "t";
                                    break;
                            };
                            break;
                        case 2:
                            switch (k)
                            {
                                case 0:
                                    mother.SideSprite[SideSprite.Up].Text = "e";
                                    mother.SideSprite[SideSprite.Right].Text = "f";
                                    mother.SideSprite[SideSprite.Down].Text = "g";
                                    mother.SideSprite[SideSprite.Left].Text = "h";
                                    break;
                                case 1:
                                    mother.SideSprite[SideSprite.Up].Text = "i";
                                    mother.SideSprite[SideSprite.Right].Text = "j";
                                    mother.SideSprite[SideSprite.Down].Text = "k";
                                    mother.SideSprite[SideSprite.Left].Text = "l";
                                    break;
                                case 2:
                                    mother.SideSprite[SideSprite.Up].Text = "m";
                                    mother.SideSprite[SideSprite.Right].Text = "n";
                                    mother.SideSprite[SideSprite.Down].Text = "o";
                                    mother.SideSprite[SideSprite.Left].Text = "p";
                                    break;
                            };
                            break;
                    };
                }
            }
        }

        public void SetInitialText(string txt)
        {
            SquareText.Text = txt;
        }

        private Sprite2D CreateSprite(string Text, Sprite2D motherSquare, MethodTextCenter center, List<Sprite2D> list, bool x)
        {
            Sprite2D Y = new Sprite2D(Vector2.Zero, Text);
            if (!x)
                Y.Position = new Vector2(Engine.RenderManager.CenterTextX(Text, "Kootenay", 0.5f,
                                        motherSquare.SizeRectangle.Width) + motherSquare.Position.X,
                                        center(motherSquare));
            else
                Y.Position = new Vector2(center(motherSquare),
                                Engine.RenderManager.CenterTextX(Text, "Kootenay", 0.5f,
                                motherSquare.SizeRectangle.Height) + motherSquare.Position.Y);
            Y.Size = Vector2Util.Half;
            list.Add(Y);            
            return Y;
        }


        public override void Update()
        {
            base.Update();

            for (int i = 0; i < Squares.Count; i++)
                Squares[i].Sprite.Update();
            for (int i = 0; i < DefaultTextsUpperCase.Count; i++)
                DefaultTextsUpperCase[i].Update();

            // Xbox Controller Thumbstick Way

            // Windows Keyboard Way / Xbox Controller DPAD Way
            bool Left = Engine.Input.IsKeyboardDown(Keys.Left) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.DPadLeft) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.LeftThumbstickLeft);
            bool Right = Engine.Input.IsKeyboardDown(Keys.Right) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.DPadRight) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.LeftThumbstickRight);
            bool Up = Engine.Input.IsKeyboardDown(Keys.Up) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.DPadUp) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.LeftThumbstickUp);
            bool Down = Engine.Input.IsKeyboardDown(Keys.Down) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.DPadDown) ||
                        Engine.Input.IsAnyPlayerButtonDown(Buttons.LeftThumbstickDown);

            bool X = Engine.Input.IsKeyboardPress(Keys.J) ||
                        Engine.Input.IsAnyPlayerButtonPress(Buttons.X);
            bool Y = Engine.Input.IsKeyboardPress(Keys.I) ||
                        Engine.Input.IsAnyPlayerButtonPress(Buttons.Y);
            bool B = Engine.Input.IsKeyboardPress(Keys.L) ||
                        Engine.Input.IsAnyPlayerButtonPress(Buttons.B);
            bool A = Engine.Input.IsKeyboardPress(Keys.K) ||
                        Engine.Input.IsAnyPlayerButtonPress(Buttons.A);

            bool LB = Engine.Input.IsKeyboardPress(Keys.N) ||
                        Engine.Input.IsButtonPress(Buttons.LeftShoulder, PlayerIndex.One);

            bool RB = Engine.Input.IsKeyboardPress(Keys.M) || 
                        Engine.Input.IsButtonPress(Buttons.RightShoulder, PlayerIndex.One);

            if (LB)
            {
                if (UpperCase)
                    SetToLowerCase();
                else
                    SetToUpperCase();
            }
            if (RB)
            {
                if (Numbers)
                    if (UpperCase)
                        SetToUpperCase();
                    else
                        SetToLowerCase();
                else
                    SetNumbers();
            }

            bool Start = Engine.Input.IsKeyboardPress(Keys.Enter) ||
                        Engine.Input.IsActivePlayerButtonPress(Buttons.Start);

            if (Start)
            {
                Callback(SquareText.Text);
            }

            for (int i = 0; i < Squares.Count; i++)
            {
                Squares[i].Sprite.Color = Color.DarkRed;
            }

            int chosen = 0;
            if (Left && Up && !Down && !Right)
            {
                // Chosen:  <- + /\
                chosen = 0;
            }
            else if (Up && !Left && !Right && !Down)
            {
                // Chosen:  /\
                chosen = 3;
            }
            else if (Up && Right && !Left && !Down)
            {
                // Chosen: -> + /\
                chosen = 6;
            }
            else if (Left && !Right && !Up && !Down)
            {
                // Chosen: <-
                chosen = 1;
            }
            else if (Right && !Left && !Up && !Down)
            {
                // Chosen: ->
                chosen = 7;
            }
            else if (Left && Down && !Up && !Right)
            {
                // Chosen: <- + \/
                chosen = 2;
            }
            else if (Down && !Left && !Right && !Up)
            {
                // Chosen: \/
                chosen = 5;
            }
            else if (Right && Down && !Left && !Up)
            {
                // Chosen -> + \/
                chosen = 8;
            }
            else
            {
                // Chosen Middle
                chosen = 4;
            }
            SquareSpriteAndChildren currentSquare = Squares[chosen];
            currentSquare.Sprite.Color = Color.Red;
            ControlSprite.Position = new Vector2(10) + currentSquare.Sprite.Position;

            if (lastChosenOne != null)
                lastChosenOne.Color = Color.White;
            Sprite2D chosenOne = null;
            if (A)
                if (currentSquare.SideSprite.ContainsKey(SideSprite.Down))
                    chosenOne = Squares[chosen].SideSprite[SideSprite.Down];
            if (Y)
                if (currentSquare.SideSprite.ContainsKey(SideSprite.Up))
                    chosenOne = Squares[chosen].SideSprite[SideSprite.Up];
            if (B)
                if (currentSquare.SideSprite.ContainsKey(SideSprite.Right))
                    chosenOne = Squares[chosen].SideSprite[SideSprite.Right];
            if (X)
                if (currentSquare.SideSprite.ContainsKey(SideSprite.Left))
                    chosenOne = Squares[chosen].SideSprite[SideSprite.Left];

            if (chosenOne != null)
            {
                lastChosenOne = chosenOne;
                chosenOne.Color = Color.Red;
                if (chosenOne.Text.Length == 1)
                {
                    SquareText.Text += chosenOne.Text;
                }
                else
                {
                    if (chosenOne.Text == "SPACE")
                        SquareText.Text += " ";
                    else if (chosenOne.Text == "<-")
                        if (SquareText.Text.Length >= 1)
                            SquareText.Text = SquareText.Text.Remove(SquareText.Text.Length - 1);
                }
            }

            TextSquare.Update();
            SquareText.Update();
            ControlSprite.Update();
        }
        private Sprite2D lastChosenOne;

        public override void Draw()
        {
            base.Draw();

            for (int i = 0; i < Squares.Count; i++)
            {
                Squares[i].Sprite.Color = BackgroundColor;
                Squares[i].Sprite.Draw();
            }

            ControlSprite.Draw();

            for (int i = 0; i < DefaultTextsUpperCase.Count; i++)
                DefaultTextsUpperCase[i].Draw();

            TextSquare.Draw();
            SquareText.Draw();

            if (!UpperCase)
                Engine.RenderManager.DrawStringWithButton(LanguageManager.GetEngineString(5), 2, 200,
                    new Vector2(50, 200), "Kootenay", Color.White, 0, Vector2.Zero, Vector2.One, 0, Vector2.One, null);
            else
                Engine.RenderManager.DrawStringWithButton(LanguageManager.GetEngineString(6), 2, 200,
                    new Vector2(50, 200), "Kootenay", Color.White, 0, Vector2.Zero, Vector2.One, 0, Vector2.One, null);
            Engine.RenderManager.DrawStringWithButton(LanguageManager.GetEngineString(7), 2, 200,
                new Vector2(50, 300), "Kootenay", Color.White, 0, Vector2.Zero, Vector2.One, 0, Vector2.One, null);
        }
    }
}
